home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload Trio 2 / Shareware Overload Trio Volume 2 (Chestnut CD-ROM).ISO / dir24 / jnos110g.zip / DOMHDR.C < prev    next >
C/C++ Source or Header  |  1994-04-17  |  15KB  |  500 lines

  1. /* Domain header conversion routines
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  *
  4.  * Additional support for the Domain Name Server
  5.  * by Johan. K. Reinalda, WG7J,
  6.  * based on previous work by Gerard v.d. Grinten, PA0GRI
  7.  */
  8. #include "global.h"
  9. #include "mbuf.h"
  10. #include "domain.h"
  11.   
  12. static int dn_expand __ARGS((char *msg,char *eom,char *compressed,char *full,
  13. int fullen));
  14. static char *getq __ARGS((struct rr **rrpp,char *msg,char *cp));
  15. static char *ntohrr __ARGS((struct rr **rrpp,char *msg,char *cp));
  16. static char *dn_compress __ARGS((char *cp,char *name));
  17. static char *htonrr __ARGS((struct rr *rr,char *buffer));
  18.   
  19. int
  20. ntohdomain(dhdr,bpp)
  21. register struct dhdr *dhdr;
  22. struct mbuf **bpp;
  23. {
  24.     int16 tmp,len;
  25.     register int16 i;
  26.     char *msg,*cp;
  27.     struct rr **rrpp;
  28.   
  29.     len = len_p(*bpp);
  30.     msg = mallocw(len);
  31.     pullup(bpp,msg,len);
  32.     memset((char *)dhdr,0,sizeof(*dhdr));
  33.   
  34.     dhdr->id = get16(&msg[0]);
  35.     tmp = get16(&msg[2]);
  36.     if(tmp & 0x8000)
  37.         dhdr->qr = 1;
  38.     dhdr->opcode = (tmp >> 11) & 0xf;
  39.     if(tmp & 0x0400)
  40.         dhdr->aa = 1;
  41.     if(tmp & 0x0200)
  42.         dhdr->tc = 1;
  43.     if(tmp & 0x0100)
  44.         dhdr->rd = 1;
  45.     if(tmp & 0x0080)
  46.         dhdr->ra = 1;
  47.     dhdr->rcode = tmp & 0xf;
  48.     dhdr->qdcount = get16(&msg[4]);
  49.     dhdr->ancount = get16(&msg[6]);
  50.     dhdr->nscount = get16(&msg[8]);
  51.     dhdr->arcount = get16(&msg[10]);
  52.   
  53.     /* Now parse the variable length sections */
  54.     cp = &msg[12];
  55.   
  56.     /* Question section */
  57.     rrpp = &dhdr->questions;
  58.     for(i=0;i<dhdr->qdcount;i++){
  59.         if((cp = getq(rrpp,msg,cp)) == NULLCHAR){
  60.             free(msg);
  61.             return -1;
  62.         }
  63.         (*rrpp)->source = RR_QUESTION;
  64.         rrpp = &(*rrpp)->next;
  65.     }
  66.     *rrpp = NULLRR;
  67.   
  68.     /* Answer section */
  69.     rrpp = &dhdr->answers;
  70.     for(i=0;i<dhdr->ancount;i++){
  71.         if((cp = ntohrr(rrpp,msg,cp)) == NULLCHAR){
  72.             free(msg);
  73.             return -1;
  74.         }
  75.         (*rrpp)->source = RR_ANSWER;
  76.         rrpp = &(*rrpp)->next;
  77.     }
  78.     *rrpp = NULLRR;
  79.   
  80.     /* Name server (authority) section */
  81.     rrpp = &dhdr->authority;
  82.     for(i=0;i<dhdr->nscount;i++){
  83.         if((cp = ntohrr(rrpp,msg,cp)) == NULLCHAR){
  84.             free(msg);
  85.             return -1;
  86.         }
  87.         (*rrpp)->source = RR_AUTHORITY;
  88.         rrpp = &(*rrpp)->next;
  89.     }
  90.     *rrpp = NULLRR;
  91.   
  92.     /* Additional section */
  93.     rrpp = &dhdr->additional;
  94.     for(i=0;i<dhdr->arcount;i++){
  95.         if((cp = ntohrr(rrpp,msg,cp)) == NULLCHAR){
  96.             free(msg);
  97.             return -1;
  98.         }
  99.         (*rrpp)->source = RR_ADDITIONAL;
  100.         rrpp = &(*rrpp)->next;
  101.     }
  102.     *rrpp = NULLRR;
  103.     free(msg);
  104.     return 0;
  105. }
  106. static char *
  107. getq(rrpp,msg,cp)
  108. struct rr **rrpp;
  109. char *msg;
  110. char *cp;
  111. {
  112.     register struct rr *rrp;
  113.     int len;
  114.     char *name;
  115.   
  116.     *rrpp = rrp = (struct rr *)callocw(1,sizeof(struct rr));
  117.     name = mallocw(512);
  118.     len = dn_expand(msg,NULLCHAR,cp,name,512);
  119.     if(len == -1){
  120.         free(name);
  121.         return NULLCHAR;
  122.     }
  123.     cp += len;
  124.     rrp->name = strdup(name);
  125.     rrp->type = get16(cp);
  126.     cp += 2;
  127.     rrp->class = get16(cp);
  128.     cp += 2;
  129.     rrp->ttl = 0;
  130.     rrp->rdlength = 0;
  131.     free(name);
  132.     return cp;
  133. }
  134. /* Read a resource record from a domain message into a host structure */
  135. static char *
  136. ntohrr(rrpp,msg,cp)
  137. struct rr **rrpp; /* Where to allocate resource record structure */
  138. char *msg;      /* Pointer to beginning of domain message */
  139. char *cp;       /* Pointer to start of encoded RR record */
  140. {
  141.     register struct rr *rrp;
  142.     int len;
  143.     char *name;
  144.   
  145.     *rrpp = rrp = (struct rr *)callocw(1,sizeof(struct rr));
  146.     name = mallocw(512);
  147.     if((len = dn_expand(msg,NULLCHAR,cp,name,512)) == -1){
  148.         free(name);
  149.         return NULLCHAR;
  150.     }
  151.     cp += len;
  152.     rrp->name = strdup(name);
  153.     rrp->type = get16(cp);
  154.     cp += 2;
  155.     rrp->class = get16(cp);
  156.     cp+= 2;
  157.     rrp->ttl = get32(cp);
  158.     cp += 4;
  159.     rrp->rdlength = get16(cp);
  160.     cp += 2;
  161.     switch(rrp->type){
  162.         case TYPE_A:
  163.         /* Just read the address directly into the structure */
  164.             rrp->rdata.addr = get32(cp);
  165.             cp += 4;
  166.             break;
  167.         case TYPE_CNAME:
  168.         case TYPE_MB:
  169.         case TYPE_MG:
  170.         case TYPE_MR:
  171.         case TYPE_NS:
  172.         case TYPE_PTR:
  173.         /* These types all consist of a single domain name;
  174.          * convert it to ascii format
  175.          */
  176.             len = dn_expand(msg,NULLCHAR,cp,name,512);
  177.             if(len == -1){
  178.                 free(name);
  179.                 return NULLCHAR;
  180.             }
  181.             rrp->rdata.name = strdup(name);
  182.             rrp->rdlength = strlen(name);
  183.             cp += len;
  184.             break;
  185.         case TYPE_HINFO:
  186.             len = *cp++;
  187.             rrp->rdata.hinfo.cpu = mallocw(len+1);
  188.             memcpy( rrp->rdata.hinfo.cpu, cp, len );
  189.             rrp->rdata.hinfo.cpu[len] = '\0';
  190.             cp += len;
  191.   
  192.             len = *cp++;
  193.             rrp->rdata.hinfo.os = mallocw(len+1);
  194.             memcpy( rrp->rdata.hinfo.os, cp, len );
  195.             rrp->rdata.hinfo.os[len] = '\0';
  196.             cp += len;
  197.             break;
  198.         case TYPE_MX:
  199.             rrp->rdata.mx.pref = get16(cp);
  200.             cp += 2;
  201.         /* Get domain name of exchanger */
  202.             len = dn_expand(msg,NULLCHAR,cp,name,512);
  203.             if(len == -1){
  204.                 free(name);
  205.                 return NULLCHAR;
  206.             }
  207.             rrp->rdata.mx.exch = strdup(name);
  208.             cp += len;
  209.             break;
  210.         case TYPE_SOA:
  211.         /* Get domain name of name server */
  212.             len = dn_expand(msg,NULLCHAR,cp,name,512);
  213.             if(len == -1){
  214.                 free(name);
  215.                 return NULLCHAR;
  216.             }
  217.             rrp->rdata.soa.mname = strdup(name);
  218.             cp += len;
  219.   
  220.         /* Get domain name of responsible person */
  221.             len = dn_expand(msg,NULLCHAR,cp,name,512);
  222.             if(len == -1){
  223.                 free(name);
  224.                 return NULLCHAR;
  225.             }
  226.             rrp->rdata.soa.rname = strdup(name);
  227.             cp += len;
  228.   
  229.             rrp->rdata.soa.serial = get32(cp);
  230.             cp += 4;
  231.             rrp->rdata.soa.refresh = get32(cp);
  232.             cp += 4;
  233.             rrp->rdata.soa.retry = get32(cp);
  234.             cp += 4;
  235.             rrp->rdata.soa.expire = get32(cp);
  236.             cp += 4;
  237.             rrp->rdata.soa.minimum = get32(cp);
  238.             cp += 4;
  239.             break;
  240.         case TYPE_TXT:
  241.         /* Just stash */
  242.             rrp->rdata.data = mallocw(rrp->rdlength);
  243.             memcpy(rrp->rdata.data,cp,rrp->rdlength);
  244.             cp += rrp->rdlength;
  245.             break;
  246.         default:
  247.         /* Ignore */
  248.             cp += rrp->rdlength;
  249.             break;
  250.     }
  251.     free(name);
  252.     return cp;
  253. }
  254.   
  255. /* Convert a compressed domain name to the human-readable form */
  256. static int
  257. dn_expand(msg,eom,compressed,full,fullen)
  258. char *msg;              /* Complete domain message */
  259. char *eom;
  260. char *compressed;       /* Pointer to compressed name */
  261. char *full;             /* Pointer to result buffer */
  262. int fullen;             /* Length of same */
  263. {
  264.     unsigned int slen;      /* Length of current segment */
  265.     register char *cp;
  266.     int clen = 0;   /* Total length of compressed name */
  267.     int indirect = 0;       /* Set if indirection encountered */
  268.     int nseg = 0;           /* Total number of segments in name */
  269.   
  270.     cp = compressed;
  271.     for(;;){
  272.         slen = uchar(*cp++);    /* Length of this segment */
  273.         if(!indirect)
  274.             clen++;
  275.         if((slen & 0xc0) == 0xc0){
  276.             if(!indirect)
  277.                 clen++;
  278.             indirect = 1;
  279.             /* Follow indirection */
  280.             cp = &msg[((slen & 0x3f)<<8) + uchar(*cp)];
  281.             slen = uchar(*cp++);
  282.         }
  283.         if(slen == 0)   /* zero length == all done */
  284.             break;
  285.         fullen -= slen + 1;
  286.         if(fullen < 0)
  287.             return -1;
  288.         if(!indirect)
  289.             clen += slen;
  290.         while(slen-- != 0)
  291.             *full++ = *cp++;
  292.         *full++ = '.';
  293.         nseg++;
  294.     }
  295.     if(nseg == 0){
  296.         /* Root name; represent as single dot */
  297.         *full++ = '.';
  298.         fullen--;
  299.     }
  300.     *full++ = '\0';
  301.     fullen--;
  302.     return clen;    /* Length of compressed message */
  303. }
  304.   
  305.   
  306.   
  307. #ifdef DOMAINSERVER
  308.   
  309. /* Most of this code is based on the DNS server in PA0GRI's 910828
  310.  * Ported to the current NOS code by Johan. K. Reinalda, WG7J
  311.  * for version and bug/feature info, see domain.c
  312.  */
  313.   
  314. static char *
  315. dn_compress(cp,name)
  316. char *cp, *name;
  317. {
  318.     int len,dlen;
  319.     char *cp1;
  320.     dlen = strlen(name);
  321.     for(;;){
  322.         /* Look for next dot */
  323.         cp1 = strchr(name,'.');
  324.         if(cp1 != NULLCHAR)
  325.             len = (int)(cp1-name); /* More to come */
  326.         else
  327.             len = dlen;     /* Last component */
  328.         *cp++ = len;            /* Write length of component */
  329.         if(len == 0)
  330.             return cp;
  331.         /* Copy component up to (but not including) dot */
  332.         strncpy(cp,name,len);
  333.         cp += len;
  334.         if(cp1 == NULLCHAR){
  335.             *cp++ = 0;      /* Last one; write null and finish */
  336.             return cp;
  337.         }
  338.         name += len+1;
  339.         dlen -= len+1;
  340.     }
  341. }
  342.   
  343. /* Translate a resource record from host format to network format */
  344. static char *
  345. htonrr(rr,buffer)
  346. struct rr *rr;
  347. char *buffer;
  348. {
  349.     struct rr *rrp;
  350.     char *cp, *p;
  351.     int i, len;
  352.   
  353.     cp = buffer;
  354.     for(rrp = rr; rrp != NULLRR; rrp = rrp->next) {
  355. #ifdef notdef
  356.         i = strlen(rrp->name);
  357.         if(rrp->name[i-1] != '.'
  358.         && rrp->origin != NULLCHAR) {
  359.             p = mallocw(i + strlen(rrp->origin) + 2);
  360.             sprintf(p,"%s.%s",rrp->name,rrp->origin);
  361.             cp = dn_compress(cp,p);
  362.             free(p);
  363.         } else
  364. #endif
  365.             cp = dn_compress(cp,rrp->name);
  366.         cp = put16(cp,rrp->type);
  367.         cp = put16(cp,rrp->class);
  368.         cp = put32(cp,rrp->ttl);
  369. #ifdef notdef
  370.     /* The length doesn't seem to be right for all types ! */
  371.         cp = put16(cp,rrp->rdlength);
  372. #endif
  373.         p = cp;     /* This is where the length goes ! */
  374.         cp += 2;    /* Save the space for lenght field */
  375.   
  376.         switch(rrp->type) {
  377.             case TYPE_A:
  378.                 cp = put32(cp,rrp->rdata.addr);
  379.                 break;
  380.             case TYPE_SOA:
  381.                 cp = dn_compress(cp,rrp->rdata.soa.mname);
  382.                 cp = dn_compress(cp,rrp->rdata.soa.rname);
  383.                 cp = put32(cp,rrp->rdata.soa.serial);
  384.                 cp = put32(cp,rrp->rdata.soa.refresh);
  385.                 cp = put32(cp,rrp->rdata.soa.retry);
  386.                 cp = put32(cp,rrp->rdata.soa.expire);
  387.                 cp = put32(cp,rrp->rdata.soa.minimum);
  388.                 break;
  389.             case TYPE_HINFO:
  390.                 *cp++ = len = strlen(rrp->rdata.hinfo.cpu);
  391.                 strncpy(cp,rrp->rdata.hinfo.cpu,len);
  392.                 cp += len;
  393.                 *cp++ = len = strlen(rrp->rdata.hinfo.os);
  394.                 strncpy(cp,rrp->rdata.hinfo.os,len);
  395.                 cp += len;
  396.                 break;
  397.             case TYPE_MX:
  398.                 cp = put16(cp,rrp->rdata.mx.pref);
  399.                 cp = dn_compress(cp,rrp->rdata.mx.exch);
  400.                 break;
  401.             case TYPE_CNAME:
  402.             case TYPE_MB:
  403.             case TYPE_MG:
  404.             case TYPE_MR:
  405.             case TYPE_NS:
  406.             case TYPE_PTR:
  407.                 cp = dn_compress(cp,rrp->rdata.data);
  408.                 break;
  409.             case TYPE_MINFO:    /* Unsupported type */
  410.                 cp = dn_compress(cp,rrp->rdata.minfo.rmailbx);
  411.                 cp = dn_compress(cp,rrp->rdata.minfo.emailbx);
  412.             case TYPE_MD:       /* Unsupported type */
  413.             case TYPE_MF:       /* Unsupported type */
  414.             case TYPE_NULL:     /* Unsupported type */
  415.             case TYPE_WKS:      /* Unsupported type */
  416.                 cp = dn_compress(cp,rrp->rdata.data);
  417.                 break;
  418.             case TYPE_TXT:
  419.             default:
  420.                 cp = put16(cp,rrp->rdlength);
  421.                 for(i=0 ; i < rrp->rdlength ; i++)
  422.                     *cp++ = rrp->rdata.data[i];
  423.                 break;
  424.         }
  425.     /* Calculate the lenght of the RR */
  426.         len = (int) (cp - p - 2);
  427.         put16(p,len);       /* and set it */
  428.     }
  429.     return cp;
  430. }
  431.   
  432. int
  433. htondomain(dhdr,buffer,buflen)
  434. struct dhdr *dhdr;
  435. char *buffer;   /* Area for query */
  436. int16 buflen;   /* Length of same */
  437. {
  438.     char *cp;
  439.     struct rr *rrp;
  440.     int16 parameter;
  441.     int i, count;
  442.   
  443.     cp = buffer;
  444.     cp = put16(cp,dhdr->id);
  445.     if(dhdr->qr)
  446.         parameter = 0x8000;
  447.     else
  448.         parameter = 0;
  449.     parameter |= (dhdr->opcode & 0x0f) << 11;
  450.     if(dhdr->aa)
  451.         parameter |= DOM_AUTHORITY;
  452.     if(dhdr->tc)
  453.         parameter |= DOM_TRUNC;
  454.     if(dhdr->rd)
  455.         parameter |= DOM_DORECURSE;
  456.     if(dhdr->ra)
  457.         parameter |= DOM_CANRECURSE;
  458.     parameter |= (dhdr->rcode & 0x0f);
  459.     cp = put16(cp,parameter);
  460.     cp = put16(cp,dhdr->qdcount);
  461.     cp = put16(cp,dhdr->ancount);
  462.     cp = put16(cp,dhdr->nscount);
  463.     cp = put16(cp,dhdr->arcount);
  464.     if((count = dhdr->qdcount) > 0) {
  465.         rrp = dhdr->questions;
  466.         for(i = 0; i < count; i++) {
  467.             cp = dn_compress(cp,rrp->name);
  468.             cp = put16(cp,rrp->type);
  469.             cp = put16(cp,rrp->class);
  470.             rrp = rrp->next;
  471.         }
  472.     }
  473.     if((count = dhdr->ancount) > 0) {
  474.         rrp = dhdr->answers;
  475.         for(i = 0; i < count; i++) {
  476.             cp = htonrr(rrp,cp);
  477.             rrp = rrp->next;
  478.         }
  479.     }
  480.     if((count = dhdr->nscount) > 0) {
  481.         rrp = dhdr->authority;
  482.         for(i = 0; i < count; i++) {
  483.             cp = htonrr(rrp,cp);
  484.             rrp = rrp->next;
  485.         }
  486.     }
  487.     if((count = dhdr->arcount) > 0) {
  488.         rrp = dhdr->additional;
  489.         for(i = 0; i < count; i++) {
  490.             cp = htonrr(rrp,cp);
  491.             rrp = rrp->next;
  492.         }
  493.     }
  494.     return (int)(cp - buffer);
  495. }
  496.   
  497.   
  498. #endif /* DOMAINSERVER */
  499.   
  500.